<template>
    <div class="table-wrapper">
        <div class="top-wrapper">
            <div class="left">
                <slot name="toolbar" :activeRows="activeRows" >

                </slot>
            </div>
            <div class="right">
                <slot name="search">
                    <el-input v-model="searchWord" style="width: 300px;cursor: pointer;" :suffix-icon="Search"  
                        placeholder="请搜索关键词, 按enter搜索" @keydown.enter="toSearch" maxlength="200" />
                </slot>
            </div>
        </div>

        <paginationTable v-bind="props" v-on="listenObj" ref="paginationTableRef" 
             :loading="loading" :data="tableData" :total="page.total" :pageNum="page.pageNum" :pageSize="page.pageSize" 
             @selection-change="onSelectionChange" @fetch-data="getData" >
            <template #operate_prefix>
                <slot name="operate_prefix"></slot>
            </template>
            <template #operate_suffix>
                <slot name="operate_suffix"></slot>
            </template>
        </paginationTable>
    </div>
    
</template>

<script lang="ts" setup>
// 页面表格： 在分页表格的基础上，增加 获取数据的方法，操作区插槽，搜索区插槽
import { tableEvents, type TableEventTypes } from './index';
import { type ConfigTableProps } from './configTable.vue';
import PaginationTable, { type QueryType, type PaginationTableProps } from './paginationTable.vue';
import { computed, reactive, ref, useSlots } from 'vue';
import { Search } from '@element-plus/icons-vue';
import request from '@/utils/request';
import type { AxiosRequestConfig, Method } from 'axios';
import { ElMessage } from 'element-plus';
import { pa } from 'element-plus/lib/locale/index.js';


export type TableResult<T=any> = {
    list: T[],
    total: number,
}

export type PageTableProps = {
    url?: string, // 请求数据的url
    urlMethod?: Method, // 请求方法
    fetchDataMthod?: (query:QueryType)=>Promise<TableResult>, // 获取数据的函数
}

const props = withDefaults(defineProps<Partial<PageTableProps&PaginationTableProps&ConfigTableProps>>(),{
    // 组件本身默认配置
    urlMethod: 'POST',

    // 复制自Pagination的默认配置
    pageSize: 10,
    pageSizeTypes: ()=>[10, 30, 50, 100],
    total: 0,
    pageNum: 1,
    layout: 'sizes, prev, pager, next, jumper',
    needPaination: true,

    // 复制自ConfigTable的默认配置；defineProps会将boolean默认值推导为false，所以这里需要手动设置为true（真坑）
    columns: () => [],
    data: () => [],
    height: 'auto',
    size: 'large',
    fit: true,
    border: true,
    emptyText: '暂无数据',
    showHeader: true,
    defaultColumnWidth: 150,
    scrollbarAlwaysOn: true,
    rowKey: 'id',
    selectable: true,
    selectColumnWidth: 50,
    selectableCall: () => true,
    sortType: 'backend',
});

// 列表数据
const tableData = ref<any[]>([]);
const loading = ref(false);
const page = reactive({
    pageNum: 1,
    pageSize: 10,
    total: 0,
});
const activeRows = ref<any[]>([]);
const searchWord = ref<string>("");

// 最底层的表格事件依然抛出
// defineEmits/definePeops 是编译时宏函数而非运行时函数，所以不能用变量，因为会报错，所以直接写死（defineProps / defineEmits vue3宏本质限制了灵活性）
const emits = defineEmits([
    // 可配置表格的事件
    'selection-change',
    'cell-click',
    'cell-dblclick',
    'row-click',
    'row-contextmenu',
    'row-dblclick',
    'header-click',
    'header-contextmenu',
    'sort-change',
    'filter-change',
    'current-change',
    'header-dragend',
    'expand-change',
]);

// 把table的事件冒泡出去
const emitEvent = (event: TableEventTypes, ...args: any[]) => {
    emits(event, ...args);
}
// 监听事件对象，直接原样抛出
const listenObj: Record<string, any> = tableEvents.reduce((obj: Record<string, any>, key: TableEventTypes) => {
    // 需要被特殊处理的事件，不能原样弹出
    if(['selection-change'].includes(key)){
        return obj;
    }
    obj[key] = (...args: any[]) => emitEvent(key, ...args);
    return obj;
}, {});


// 获取子组件的实例类型
const paginationTableRef = ref<InstanceType<typeof PaginationTable>>();

const onSelectionChange = (selection: any[]) => {
    activeRows.value = selection;
}

const getData = (query:QueryType) => {
    page.pageNum = query.page.pageNum;
    page.pageSize = query.page.pageSize;

    if(props.url){
        const req:AxiosRequestConfig = {
            url: props.url,
            method: props.urlMethod,   
        }
        if(req.method=='GET'||req.method=='DELETE'){
            req.params = query;
        }else{
            req.data = query;
        }
        loading.value = true;
        return request(req).finally(()=>{
            loading.value = false;
        });
    }else if(props.fetchDataMthod){
        loading.value = true;
        return props.fetchDataMthod.call(paginationTableRef.value, query).then(res=>{
            tableData.value = res.list;
            page.total = res.total;
        }).finally(()=>{
            loading.value = false;
        });
    }else if(props.data){
        // 直接设置数据，不启用分页
        tableData.value = props.data;
    }else{
        console.error('请设置获取数据的url、获取数据的方法或者数据列表');
    }
}

const toSearch = ()=>{
    const text = searchWord.value.trim();
    if(text){
        return paginationTableRef.value?.setSerchParams({ keyWords: text });
    }else{
        return ElMessage.error("请输入有效内容");
    }
}

const setSearchObj = (obj:Record<string, any>)=>{
    return paginationTableRef.value?.setSerchParams(obj);
}

defineExpose({
    getTableInstance: () => paginationTableRef.value?.getTableInstance(),
    setSerchParams: (params: any) => paginationTableRef.value?.setSerchParams(params),
    getQuery: () => paginationTableRef.value?.getQuery(),
    setSearchObj,
    refresh: (reset?:boolean)=>paginationTableRef.value?.getData(reset),
});
</script>

<style lang="scss" scoped>
.top-wrapper{
    margin-top: 20px;
    margin-bottom: 20px;
    display: flex;
    justify-content: space-between;
}
</style>